//
// Created on 2024/12/30.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#ifndef RLOTTIE_DEMO_XCOMPONENT_H
#define RLOTTIE_DEMO_XCOMPONENT_H

#include "ArkUINode.h"
#include "string"
#include <ace/xcomponent/native_interface_xcomponent.h>
#include <cstdint>
#include <cstdio>
#include <hilog/log.h>
#include <string>
#include "arkui/native_node.h"
#include "arkui/native_node_napi.h"
#include "arkui/native_interface.h"
#include <native_drawing/drawing_font_collection.h>
#include <native_drawing/drawing_text_typography.h>
#include <native_buffer/native_buffer.h>
#include <map>
#include <sys/mman.h>
#include <native_drawing/drawing_bitmap.h>
#include <native_drawing/drawing_color.h>
#include <native_drawing/drawing_color_filter.h>
#include <native_drawing/drawing_canvas.h>
#include <native_drawing/drawing_pen.h>
#include <native_drawing/drawing_pixel_map.h>
#include <native_drawing/drawing_brush.h>
#include <native_drawing/drawing_path.h>
#include <native_drawing/drawing_rect.h>
#include <native_drawing/drawing_register_font.h>
#include <native_drawing/drawing_filter.h>
#include <native_drawing/drawing_font.h>
#include <native_drawing/drawing_font_collection.h>
#include <native_drawing/drawing_sampling_options.h>
#include <native_drawing/drawing_text_blob.h>
#include <native_drawing/drawing_text_declaration.h>
#include <native_drawing/drawing_text_typography.h>
#include <native_drawing/drawing_types.h>
#include <native_drawing/drawing_typeface.h>
#include "native_drawing/drawing_image.h"
#include <chrono>
#include <iostream>
#include "Getrlottie.h"
#include <cstring> 

// 需要创建全局变量 然后使用 playFrame

namespace NativeModule {

OHNativeWindow *g_nativeWindow_ = nullptr;

class XcomponentNode : public ArkUINode {
public:
    std::string FileName;
    OH_NativeXComponent_Callback callback_;
    Glottie *Lalrlottie = new Glottie;
    int32_t FrameNum = 0;

    XcomponentNode(float width, float height, std::string fileName)
        : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_XCOMPONENT))
    {

        width_ = width * 3.25;
        height_ = height * 3.25;
//         width_ = 975;
//         height_ = 975;
        FileName = fileName;
        ArkUI_NumberValue valueSize[] = {480};
        ArkUI_NumberValue value1[] = {{.u32 = 15}, {.f32 = 15}};
        ArkUI_AttributeItem itemSize = {valueSize, 1};
        ArkUI_NumberValue value[] = {480};
        ArkUI_AttributeItem item = {value, 1, "changeSize"};
        ArkUI_AttributeItem item2 = {value, 1, "ndkxcomponent"};
        ArkUI_AttributeItem item1 = {value1, 2};

        callback_.OnSurfaceCreated = OnSurfaceCreated;
        callback_.OnSurfaceChanged = OnSurfaceChanged;
        callback_.OnSurfaceDestroyed = OnSurfaceDestroyed;
        callback_.DispatchTouchEvent = DispatchTouchEvent;

        ArkUI_NumberValue focusable[] = {1};
        focusable[0].i32 = 1;
        ArkUI_AttributeItem focusableItem = {focusable, 1};

        value[0].u32 = ARKUI_XCOMPONENT_TYPE_SURFACE;
        nativeModule_->setAttribute(handle_, NODE_XCOMPONENT_TYPE, &item);
        nativeModule_->setAttribute(handle_, NODE_XCOMPONENT_ID, &item);
        nativeModule_->setAttribute(handle_, NODE_XCOMPONENT_SURFACE_SIZE, &item1);
        nativeModule_->setAttribute(handle_, NODE_FOCUSABLE, &focusableItem);

        valueSize[0].f32 = width;
        itemSize = {valueSize, 1};
        nativeModule_->setAttribute(handle_, NODE_WIDTH, &itemSize);
        valueSize[0].f32 = height;
        itemSize = {valueSize, 1};
        nativeModule_->setAttribute(handle_, NODE_HEIGHT, &itemSize);

        nativeModule_->setAttribute(handle_, NODE_ID, &item2);
        auto *nativeXComponent = OH_NativeXComponent_GetNativeXComponent(handle_);

        if (!nativeXComponent) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "GetNativeXComponent error");
        }
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "GetNativeXComponent success");

        OH_NativeXComponent_RegisterCallback(nativeXComponent, &callback_);

        auto typeRet = nativeModule_->getAttribute(handle_, NODE_XCOMPONENT_TYPE);
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "xcomponent type: %{public}d",
                     typeRet->value[0].i32);
        auto idRet = nativeModule_->getAttribute(handle_, NODE_XCOMPONENT_ID);
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "xcomponent id: %{public}s", idRet->string);

        Lalrlottie->InitFormFile(FileName);
        Lalrlottie->PrintInfo();
    }

    // CApi XComponent
    static void OnSurfaceChanged(OH_NativeXComponent *component, void *window)
    {
//         int32_t ret = OH_NativeXComponent_GetXComponentSize(component, window, &width_, &height_);
//         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "XComponent_Native",
//              "OnSurfaceChanged ret=%{public}d width=%{public}lu, height=%{public}lu", ret, width_, height_);
    }

    static void OnSurfaceDestroyed(OH_NativeXComponent *component, void *window)
    {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "XComponent_Native", "PluginManager::OnSurfaceDestroyed");
    }
    static void DispatchTouchEvent(OH_NativeXComponent *component, void *window)
    {
    }

    static void OnSurfaceCreated(OH_NativeXComponent *component, void *window)
    {
        uint64_t width_;
        uint64_t height_;
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "XComponent_Native", "PluginManager::OnSurfaceCreated");
        int32_t ret;
        char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
        uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
        ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize);
        ret = OH_NativeXComponent_GetXComponentSize(component, window, &width_, &height_);
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "XComponent_Native",
                     "OnSurfaceChanged ret=%{public}d width=%{public}lu, height=%{public}lu", ret, width_, height_);
        if (ret == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
            g_nativeWindow_ = static_cast<OHNativeWindow *>(window);
        }
    }

    // 初始化画布的操作，与下面的渲染配合，要先执行初始化
    void Prepare()
    {
        int32_t usage = NATIVEBUFFER_USAGE_CPU_READ | NATIVEBUFFER_USAGE_CPU_WRITE | NATIVEBUFFER_USAGE_MEM_DMA;

        int ret = OH_NativeWindow_NativeWindowHandleOpt(g_nativeWindow_, SET_USAGE, usage);
        if (ret != 0) {
            DRAWING_LOGE("failed to OH_NativeWindow_NativeWindowHandleOpt");
            return;
        }
        // 通过 OH_NativeWindow_NativeWindowRequestBuffer 获取 OHNativeWindowBuffer 实例
        ret = OH_NativeWindow_NativeWindowRequestBuffer(g_nativeWindow_, &buffer_, &fenceFd_);
        DRAWING_LOGE("request buffer ret = %{public}d", ret);
        // 通过 OH_NativeWindow_GetBufferHandleFromNative 获取 buffer 的 handle
        bufferHandle_ = OH_NativeWindow_GetBufferHandleFromNative(buffer_);
        mappedAddr_ = static_cast<uint32_t *>(mmap(bufferHandle_->virAddr, bufferHandle_->size, PROT_READ | PROT_WRITE,
                                                   MAP_SHARED, bufferHandle_->fd, 0));
        if (mappedAddr_ == MAP_FAILED) {
            DRAWING_LOGE("mmap failed");
        }
    }

    void PlayFrame(int32_t frameNum)
    {
        FrameNum = frameNum;
        int32_t usage = NATIVEBUFFER_USAGE_CPU_READ | NATIVEBUFFER_USAGE_CPU_WRITE | NATIVEBUFFER_USAGE_MEM_DMA;
        int ret = OH_NativeWindow_NativeWindowHandleOpt(g_nativeWindow_, SET_USAGE, usage);
        if (ret != 0) {
            DRAWING_LOGE("failed to OH_NativeWindow_NativeWindowHandleOpt");
            return;
        }
        // 通过 OH_NativeWindow_NativeWindowRequestBuffer 获取 OHNativeWindowBuffer 实例
        ret = OH_NativeWindow_NativeWindowRequestBuffer(g_nativeWindow_, &buffer_, &fenceFd_);
        DRAWING_LOGE("request buffer ret = %{public}d", ret);
        // 通过 OH_NativeWindow_GetBufferHandleFromNative 获取 buffer 的 handle
        bufferHandle_ = OH_NativeWindow_GetBufferHandleFromNative(buffer_);
        mappedAddr_ = static_cast<uint32_t *>(mmap(bufferHandle_->virAddr, bufferHandle_->size, PROT_READ | PROT_WRITE,
                                                   MAP_SHARED, bufferHandle_->fd, 0));
        if (mappedAddr_ == MAP_FAILED) {
            DRAWING_LOGE("mmap failed");
        }
        //----------------------------------------这个上面是初始化---------------

        auto now = std::chrono::high_resolution_clock::now();
        auto startTime = std::chrono::time_point_cast<std::chrono::nanoseconds>(now).time_since_epoch();

        uint32_t *resces = reinterpret_cast<uint32_t *>(Lalrlottie->RenderFrame(FrameNum, width_, height_));
        now = std::chrono::high_resolution_clock::now();
        auto getTime = std::chrono::time_point_cast<std::chrono::nanoseconds>(now).time_since_epoch();
        DRAWING_LOGE("\n\n\n解析用时%{public}5.2fms", (getTime - startTime) / 1000000.0);

        uint32_t *pixel = static_cast<uint32_t *>(mappedAddr_); // 使用mmap获取到的地址来访问内存
        if (pixel == nullptr) {
            DRAWING_LOGE("pixel is null");
            return;
        }
        memcpy(pixel, resces, width_ * height_ * 4);

        Region region{nullptr, 0};
        // 通过OH_NativeWindow_NativeWindowFlushBuffer 提交给消费者使用，例如：显示在屏幕上。
        OH_NativeWindow_NativeWindowFlushBuffer(g_nativeWindow_, buffer_, fenceFd_, region);
        //----------------------------------------------这个下面是回收内存----------------
        // 回收内存的操作
        int result = munmap(mappedAddr_, bufferHandle_->size);
        if (result == -1) {
            DRAWING_LOGE("munmap failed!");
        }
        OH_Drawing_CanvasDestroy(cCanvas_);
        cCanvas_ = nullptr;
        // 销毁bitmap对象
        OH_Drawing_BitmapDestroy(cBitmap_);

        now = std::chrono::high_resolution_clock::now();
        auto endTime = std::chrono::time_point_cast<std::chrono::nanoseconds>(now).time_since_epoch();
        DRAWING_LOGE("\n\n\n渲染用时%{public}5.2fms", (endTime - getTime) / 1000000.0);
    }

private:
    int width_;
    int height_;
    static XcomponentNode *xcomponentNode_;
    OH_Drawing_Bitmap *cBitmap_ = nullptr;
    OH_Drawing_Canvas *cCanvas_ = nullptr;
    uint32_t *mappedAddr_ = nullptr;
    int fenceFd_ = 0;
    struct NativeWindowBuffer *buffer_ = nullptr;
    BufferHandle *bufferHandle_ = nullptr;
};

} // namespace NativeModule

#endif // RLOTTIE_DEMO_XCOMPONENT_H
